import asyncio
import logging
import os
from typing import Any, List

import speedtest
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.orm import joinedload
from starlette.requests import Request
from starlette_admin import EnumField, action
from starlette_admin.contrib.sqla import ModelView
from starlette_admin.exceptions import ActionFailed

from src.application.order.enums import AuthorizationType, ProxyStatus, ReloadType
from src.infrastructure.db.models import Proxy

logger = logging.getLogger(__name__)


class ProxyView(ModelView):
    fields = [
        "id",
        "server",
        EnumField("status", enum=ProxyStatus, select2=False),
        "port_https",
        "login",
        "password",
        "orders",
        "users",
        EnumField("authorization_type", enum=AuthorizationType, select2=False),
        EnumField("reload_type", enum=ReloadType, select2=False),
        "reload_period",
        "reload_link",
        "was_added",
    ]
    fields_default_sort = [Proxy.id, ("id", True)]
    actions = ["check_speed"]

    @action(
        name="check_speed",
        text="Check speed",
    )
    async def check_proxy_view(self, request: Request, pks: List[Any]):
        session: AsyncSession = request.state.session
        for proxy_id in pks:
            res = await session.execute(select(Proxy).where(Proxy.id == proxy_id).options(joinedload(Proxy.server)))
            proxy = res.scalar()
            try:
                os.environ[
                    "HTTP_PROXY"
                ] = f"http://{proxy.login}:{proxy.password}@{proxy.server.ip_address}:{proxy.port_https}"
                os.environ[
                    "HTTPS_PROXY"
                ] = f"http://{proxy.login}:{proxy.password}@{proxy.server.ip_address}:{proxy.port_https}"
                os.environ[
                    "http_proxy"
                ] = f"http://{proxy.login}:{proxy.password}@{proxy.server.ip_address}:{proxy.port_https}"
                os.environ[
                    "https_proxy"
                ] = f"http://{proxy.login}:{proxy.password}@{proxy.server.ip_address}:{proxy.port_https}"

                st = await asyncio.to_thread(speedtest.Speedtest)
                await asyncio.to_thread(st.get_best_server)
                download_speed = round(await asyncio.to_thread(st.download) / 1e6, 2)
                upload_speed = round(await asyncio.to_thread(st.upload) / 1e6, 2)

                return (f"Proxy: {proxy.id}. Download speed: {download_speed} Mbps. Upload speed: {upload_speed} Mbps",)
            except Exception as e:
                logger.exception(e)
                return ActionFailed(f"Failed to speed of proxy №{proxy.id}")
